package com.heima.comment.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.comment.dtos.CommentLikeDto;
import com.heima.comment.dtos.CommentListDto;
import com.heima.comment.dtos.CommentSaveDto;
import com.heima.comment.pojos.ApComment;
import com.heima.comment.pojos.ApCommentLike;
import com.heima.comment.pojos.ApCommentVo;
import com.heima.comment.service.CommentService;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.constants.HotArticleConstants;
import com.heima.feign.client.UserFeginClient;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.message.UpdateArticleMess;
import com.heima.model.user.pojos.ApUser;
import com.heima.utils.threadlocal.ApThreadLocal;
import org.bson.types.ObjectId;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.mongodb.core.query.UpdateDefinition;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import springfox.documentation.spring.web.json.Json;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class CommentServiceImpl implements CommentService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private UserFeginClient userFeginClient;

    @Autowired
    private GreenTextScan textScan;

    @Autowired
    private KafkaTemplate<String,String> kafkaTemplate;


    /**
     * 保存评论列表
     * @param dto
     * @return
     */
    @Override
    public ResponseResult saveComment(CommentSaveDto dto) {

        //1.参数校验
        if(dto.getArticleId()==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        if(dto.getContent()==null || dto.getContent().length()>140){
            return ResponseResult.errorResult(AppHttpCodeEnum.COMMENT_FAILE);
        }

        //2.获取登录用户id,此时的apUser对象中只包含用户id
        ApUser apUser = ApThreadLocal.getApUser();
        //表示未登录
        if(apUser==null){
            return ResponseResult.okResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        //游客身份不能进行以下操作
        if(apUser.getId()==0){
            return ResponseResult.okResult(405,"游客身份禁止，需进行登录");
        }
        //3.查询redis是否有用户信息，如果没有，则调用feign，如果有则直接使用
            //定义key ,value就是当前用户信息的实体类
        String comment_key="LOGIN_USER_"+apUser.getId();
            //查询当前redis中是否存在当前缓存
        String apUserStr = redisTemplate.opsForValue().get(comment_key);
        if(apUserStr==null){//表示不存在，则调用feign
            //调用feign接口
            ResponseResult<ApUser>responseResult = userFeginClient.findUserById(apUser.getId());
            if(responseResult.getCode()==200){
                apUser = responseResult.getData();

                //把获取的用户信息保存到redis中一份
                redisTemplate.opsForValue().set(comment_key,JSON.toJSONString(apUser),2, TimeUnit.HOURS);
            }
        }else{//redis中存在，如果有则直接使用
            apUser= JSON.parseObject(apUserStr,ApUser.class);
        }


        //4.对发布评论内容要进行文本审核
      Boolean flag=  contentTextScan(dto.getContent());
        if(!flag){
            return ResponseResult.errorResult(AppHttpCodeEnum.COMMENT_CONTENT_FAILE);
        }

        //4.封装数据插入到mongo中
        ApComment apComment=new ApComment();
        apComment.setContent(dto.getContent());
        apComment.setCreatedTime(new Date());
        apComment.setId(ObjectId.get().toHexString());
        apComment.setImage(apUser.getImage());
        apComment.setLikes(0);//评论的点赞数量
        apComment.setReply(0);//评论的回复数量
        apComment.setNickName(apUser.getName());
        apComment.setTargetId(dto.getArticleId()+"");
        apComment.setUpdatedTime(new Date());
        apComment.setUserId(apUser.getId());
        mongoTemplate.insert(apComment);

        //发送消息
        UpdateArticleMess mess=new UpdateArticleMess();
        mess.setAdd(1);
        mess.setType(UpdateArticleMess.UpdateArticleType.COMMENT);
        mess.setArticleId(dto.getArticleId());

        kafkaTemplate.send(HotArticleConstants.HOT_ARTICLE_SCORE_TOPIC, JSON.toJSONString(mess));


        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }



    /**
     * 对发表评论内容的审核
     * @param content
     * @return
     */
    private Boolean contentTextScan(String content) {
        boolean flag=true;

        try {
            Map map = textScan.greeTextScan(content);
            if(!map.get("suggestion").equals("pass")){
                flag=false;
            }
        } catch (Exception e) {
            e.printStackTrace();
            flag=false;
        }
        return flag;
    }



    /**
     * 评论点赞
     * @param dto
     * @return
     */
    @Override
    public ResponseResult like(CommentLikeDto dto) {
        //1.检查参数
        if (dto.getCommentId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }

        //2.判断是否登录
        ApUser apUser = ApThreadLocal.getApUser();
        if (apUser == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        //2.5 判断如果是游客身份则不允许发表评论
        if(apUser.getId()==0){
            return  ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN,"请登录之后再来点赞！！");
        }

        //判断当前评论信息是否存在，如果不存在，直接返回
        ApComment apComment = mongoTemplate.findById(dto.getCommentId(), ApComment.class);
        if(apComment==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }


        //3.查询redis,是否有点赞过
            //定义key
        String comment_likes_key="COMMENT_LIKE_"+apUser.getId();
        //表示根据当前key下的所有的value中是否包含某一个，如果包含返回true,否则false
        Boolean memberFlag = redisTemplate.opsForSet().isMember(comment_likes_key, dto.getCommentId());

        //4 如果点赞过，并且现在正在执行的是点赞操作，直接返回
        if(memberFlag && dto.getOperation()==0){
            return ResponseResult.okResult(AppHttpCodeEnum.COMMENT_LIKES_END_SUCCESS);
        }
        //5  如果点赞过，并且正在执行的是取消点赞，删除redis,删除mongo中点赞集合，修改mongo中的评论集合，点赞数-1
        if(memberFlag && dto.getOperation()==1){
            //删除redis
            redisTemplate.opsForSet().remove(comment_likes_key,dto.getCommentId());
            //删除mongo中点赞集合
            mongoTemplate.remove(
                    Query.query(Criteria.where("userId").is(apUser.getId()).and("targetId").is(dto.getCommentId()))
                    , ApCommentLike.class);

            //修改mongo中的评论集合，点赞数-1
            Query query=Query.query(Criteria.where("id").is(apComment.getId()).and("likes").gt(0));
            UpdateDefinition update=new Update().inc("likes",-1);
            mongoTemplate.updateFirst(query,update,ApComment.class);
        }
        //6 如果没有点赞过，并且正在执行的是点赞操作，新增redis,新增mongo中的点赞集合，修改mongo中的评论集合，点赞数+1
        if(!memberFlag && dto.getOperation()==0){
            //新增redis
            redisTemplate.opsForSet().add(comment_likes_key,dto.getCommentId());
            //新增mongo中的点赞集合
            ApCommentLike apCommentLike=new ApCommentLike();
            apCommentLike.setId(ObjectId.get().toHexString());
            apCommentLike.setTargetId(dto.getCommentId());
            apCommentLike.setCreatedTime(new Date());
            apCommentLike.setUserId(apUser.getId());
            mongoTemplate.insert(apCommentLike);
            //修改mongo中的评论集合，点赞数+1
            Query query=Query.query(Criteria.where("id").is(apComment.getId()));
            UpdateDefinition update=new Update().inc("likes",1);
            mongoTemplate.updateFirst(query,update,ApComment.class);
        }
        //4.返回数据
        apComment = mongoTemplate.findById(dto.getCommentId(), ApComment.class);

        Map map=new HashMap();
        map.put("likes",apComment.getLikes());

        return ResponseResult.okResult(map);
    }

    /**
     * 查询评论列表
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult findByArticleId(CommentListDto dto) {

        //1.参数校验
        if(dto.getArticleId()==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        if(dto.getSize()==null || dto.getSize()<=0){
            dto.setSize(10);
        }
        dto.setSize(Math.min(dto.getSize(),50));

        //2.查询mongo
        List<ApComment> apComments = mongoTemplate.find(
                Query.query(Criteria.where("targetId").is(dto.getArticleId()).and("createdTime").lt(dto.getMinDate()))
                        .with(Sort.by(Sort.Direction.DESC, "createdTime"))
                        .limit(dto.getSize()).skip((dto.getIndex()-1)*dto.getSize()),
                ApComment.class);

        //添加标记
        ApUser apUser = ApThreadLocal.getApUser();
        if (apUser == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        //2.5 判断如果是游客身份则直接返回列表
        if(apUser.getId()==0){
            return ResponseResult.okResult(apComments);
        }
        //判断当前用户是否点赞过该评论
        String comment_likes_key="COMMENT_LIKE_"+apUser.getId();
        //表示根据当前key下的所有的value的集合
        Set<String> commentIdSet = redisTemplate.opsForSet().members(comment_likes_key);

        //4.2 如果没有查询到数据,则直接返回评论列表
        if(commentIdSet==null){
            return ResponseResult.okResult(apComments);
        }

        //对apComments进行遍历操作，然后比较
        List<ApCommentVo> apCommentVos = apComments.stream().map(comment -> {
            ApCommentVo vo = new ApCommentVo();
            BeanUtils.copyProperties(comment, vo);
            if (commentIdSet.contains(comment.getId())) {
                vo.setOperation((short) 0);
            }
            return vo;
        }).collect(Collectors.toList());


        //3.封装数据并返回
        return ResponseResult.okResult(apCommentVos);
    }
}
